﻿using ClosedXML.Excel;
using log4net;
using Newtonsoft.Json;
using OPCTreeMonitor.Config;
using OPCTreeMonitor.SQLdb.dbConnect;
using OPCTreeMonitor.SQLdb.dbModel;
using OPCTreeMonitor.SQLdb.Infrastructure;
using OPCTreeMonitor.ToPLC;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using Workbook = Spire.Xls.Workbook;

namespace OPCTreeMonitor
{
    public class OPCMethod
    {
        #region 单例模式
        private static readonly object Lock = new object();
        private static OPCMethod _instance;
        public static OPCMethod Instance
        {
            get
            {
                lock (Lock)
                {
                    if (_instance == null)
                    {
                        _instance = new OPCMethod();
                    }
                }
                return _instance;
            }
        }
        #endregion

        public OPCStorageModel ConfigDbs { get; private set; }
        private List<KeyValuePair<string, ILog>> _Loggers;

        public void ConncetConfigDb()
        {
            try
            {
                // 初始化数据库连接
                var db = SqliteDbHelper.Db;
                ConfigDbs = new OPCStorageModel(db);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"数据库连接失败: {ex.Message}", "错误",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                OPCMethod.Instance.GetLogByName("App").Error($"数据库连接失败: ", ex);
                return;
            }
        }

        #region 配置
        public void ReadConfig()
        {
            ReadCommonConfig();
            BuildPLC();
        }
        private void ReadCommonConfig()
        {
            lock (_lock)
            {
                var workflowConfigPath = $"{AppDomain.CurrentDomain.BaseDirectory}Config\\CommonConfig.json";
                if (!File.Exists(workflowConfigPath))
                {
                    JsonOperation.WriteToJsonFile(new CommonConfig(), workflowConfigPath);
                }
                CommonConfigs = JsonOperation.ReadConfigFromFile<CommonConfig>(workflowConfigPath);
            }
        }
        public IPLC GetPlcByName(string name)
        {
            return Plc.FirstOrDefault(x => x.Name == name);
        }
        public IPLC GetPlcByIndex(int index)
        {
            var plc = Plc.FirstOrDefault(x => x.Index == index);
            return plc;
        }
        public int GetPlcIndex(string name)
        {
            if (Plc.Any(x => x.Name == name))
            {
                return Plc.FirstOrDefault(x => x.Name == name).Index;
            }
            else
            {
                return -1;
            }
        }
        #region 配置日志记录
        public void InitializeIlog()
        {
            log4net.Config.XmlConfigurator.Configure(new FileInfo(System.IO.Path.GetFullPath(@"Config/log4.xml")));
            _Loggers = LogManager.GetCurrentLoggers()
                                            .Select(x => new KeyValuePair<string, ILog>(x.Logger.Name, x))
                                            .ToList();
        }
        public ILog GetLogByName(string name)
        {
            if (!_Loggers.Any(x => x.Key == "App"))
            {
                throw new Exception($"不存在默认日志App");
            }
            if (!_Loggers.Any(x => x.Key == name))
            {
                return _Loggers.FirstOrDefault(x => x.Key == "App").Value;
            }
            else
            {
                return _Loggers.FirstOrDefault(x => x.Key == name).Value;
            }
        }
        #endregion
        #endregion
        #region 初始化
        private object _lock = new object();
        public List<IPLC> Plc = new List<IPLC>();
        public CommonConfig CommonConfigs { get; set; } = new CommonConfig();

        public string plcAddress;
        public bool ThreadRunning = true;
        public void StartUpdate()
        {
            foreach (var item in Plc)
            {
                Task.Run(() =>
                {
                    Update(item);
                });
            }

        }
        private void BuildPLC()
        {
            foreach (var plc in CommonConfigs.PLCS)
            {
                switch (plc.TYPE)
                {
                    case PLCType.OPC:
                        var p = new OPCPLC(plc.Name, plc.Index);
                        p.SetConnectionStr(plc.ConnectStr);
                        plcAddress = plc.ConnectStr;
                        Plc.Add(p);
                        break;
                    case PLCType.ADS:
                        break;
                    default:
                        break;
                }
            }
        }
        public void Connect()
        {
            var errorMessages = new List<string>();
            foreach (var item in Plc)
            {
                try
                {
                    item.Connect();
                }
                catch (Exception ex)
                {
                    OPCMethod.Instance.GetLogByName("App").Error($"连接 {item.Name} 失败: {ex.Message}");
                }
            }
            if (errorMessages.Count > 0)
            {
                var errorMessage = string.Join(Environment.NewLine, errorMessages);
                MessageBox.Show($"部分 PLC 连接失败: {errorMessage}");
                OPCMethod.Instance.GetLogByName("App").Error($"部分 PLC 连接失败:{errorMessage}");

            }
        }
        private void Update(object e)
        {
            while (ThreadRunning)
            {
                var item = e as IPLC;
                try
                {
                    if (item != null && item.Connected)
                    {
                        item?.Update();
                    }
                }
                catch (Exception ex)
                {
                    Thread.Sleep(1000);
                }
                Thread.Sleep(100);
            }
        }
        #endregion

        #region 开始数据记录
        public void InitialLogInstance()
        {
            CatchThreadStart();
        }
        private void CatchThreadStart()
        {
            StartLoggingTasks();//数据记录线程
        }


        /// <summary>
        /// 开启日志记录任务
        /// </summary>
        private async void StartLoggingTasks()
        {
            if (OPCMethod.Instance.GetPlcByIndex(0) != null && OPCMethod.Instance.GetPlcByIndex(0).Connected)
            {
                await Task.WhenAll(
                LogRuntimeTask(),
                LogAutoEventTimeSave(),
                LogActPowerTask(),
                C1LogWorkingTask(),
                C2LogWorkingTask(),
                C3LogWorkingTask(),
                C4LogWorkingTask(),
                C5LogWorkingTask(),
                LogToCsvWorkingTask()

                );
            }

        }
        #region 实时数据写入
        /// <summary>
        /// 实时数据日志任务
        /// </summary>
        private async Task LogRuntimeTask()
        {
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "实时数据");
                    var lis = GetLogData(nodes);
                    lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    //excel_CSV_Write(lis.ToArray(), "实时数据", 2);
                    await excel_CSV_WriteAsync(lis.ToArray(), "实时数据", 5);

                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"实时数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task LogAutoEventTimeSave()
        {
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "半自动流程计时");
                    var lis = GetLogData(nodes);
                    lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    //excel_CSV_Write(lis.ToArray(), "实时数据", 2);
                    await excel_CSV_WriteAsync(lis.ToArray(), "半自动流程计时", 7);

                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"半自动流程计时数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task LogActPowerTask()
        {
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "电表数据");
                    var lis = GetLogData(nodes);
                    lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    //excel_CSV_Write(lis.ToArray(), "实时数据", 2);
                    await excel_CSV_WriteAsync(lis.ToArray(), "电表数据", 6);

                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"电表数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }

        private async Task C1LogWorkingTask()
        {
            bool isBuidNewFile = false;
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    if (OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL_Auto.C1_AutoProcess.Doing") == "True")//工艺数据开始触发信号
                    {
                        //if (!isBuidNewFile)
                        //{
                        //    isBuidNewFile = true;
                        //    await excel_CSV_WriteLineAsync(string.Empty, "C1工艺中数据", 0);
                        //    //await excel_CSV_WriteLineAsync($"工艺开始:{DateTime.Now}", "C1工艺中数据", 0);
                        //}
                        var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "C1工艺中数据");
                        var lis = GetLogData(nodes);
                        lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        await excel_CSV_WriteAsync(lis.ToArray(), "C1工艺中数据", 0);
                    }
                    else
                    {
                        isBuidNewFile = false;
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"C1工艺中数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task C2LogWorkingTask()
        {
            bool isBuidNewFile = false;
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    if (OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL_Auto.C2_AutoProcess.Doing") == "True")//工艺数据开始触发信号
                    {
                        //if (!isBuidNewFile)
                        //{
                        //    isBuidNewFile = true;
                        //    await excel_CSV_WriteLineAsync(string.Empty, "C2工艺中数据", 1);
                        //    //await excel_CSV_WriteLineAsync($"工艺开始:{DateTime.Now}", "C2工艺中数据", 1);
                        //}
                        var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "C2工艺中数据");
                        var lis = GetLogData(nodes);
                        lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        await excel_CSV_WriteAsync(lis.ToArray(), "C2工艺中数据", 1);
                    }
                    else
                    {
                        isBuidNewFile = false;
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"C2工艺中数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task C3LogWorkingTask()
        {
            bool isBuidNewFile = false;
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    if (OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL_Auto.C3_AutoProcess.Doing") == "True")//工艺数据开始触发信号
                    {
                        //if (!isBuidNewFile)
                        //{
                        //    isBuidNewFile = true;
                        //    await excel_CSV_WriteLineAsync(string.Empty, "C3工艺中数据", 2);
                        //    //await excel_CSV_WriteLineAsync($"工艺开始:{DateTime.Now}", "C3工艺中数据", 2);
                        //}
                        var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "C3工艺中数据");
                        var lis = GetLogData(nodes);
                        lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        await excel_CSV_WriteAsync(lis.ToArray(), "C3工艺中数据", 2);
                    }
                    else
                    {
                        isBuidNewFile = false;
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"C3工艺中数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task C4LogWorkingTask()
        {
            bool isBuidNewFile = false;
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    if (OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL_Auto.C4_AutoProcess.Doing") == "True")//工艺数据开始触发信号
                    {
                        //if (!isBuidNewFile)
                        //{
                        //    isBuidNewFile = true;
                        //    await excel_CSV_WriteLineAsync(string.Empty, "C4工艺中数据", 3);
                        //    //await excel_CSV_WriteLineAsync($"工艺开始:{DateTime.Now}", "C4工艺中数据", 3);
                        //}
                        var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "C4工艺中数据");
                        var lis = GetLogData(nodes);
                        lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        await excel_CSV_WriteAsync(lis.ToArray(), "C4工艺中数据", 3);
                    }
                    else
                    {
                        isBuidNewFile = false;
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"C4工艺中数据记录失败", ex);
                }
                await Task.Delay(1000);
            }
        }
        private async Task C5LogWorkingTask()
        {
            bool isBuidNewFile = false;
            while (ThreadRunning)
            {
                if (!ThreadRunning)
                    break;
                try
                {
                    if (OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL_Auto.C5_AutoProcess.Doing") == "True")//工艺数据开始触发信号
                    {
                        //if (!isBuidNewFile)
                        //{
                        //    isBuidNewFile = true;
                        //    await excel_CSV_WriteLineAsync(string.Empty, "C5工艺中数据", 4);
                        //    //await excel_CSV_WriteLineAsync($"工艺开始:{DateTime.Now}", "C5工艺中数据", 4);
                        //}
                        var nodes = OPCMethod.Instance.ConfigDbs.LogRecordRepository.Where(x => x.SheetName == "C5工艺中数据");

                        var lis = GetLogData(nodes);
                        lis.Insert(0, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        await excel_CSV_WriteAsync(lis.ToArray(), "C5工艺中数据", 4);
                    }
                    else
                    {
                        isBuidNewFile = false;
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"C5工艺中数据记录失败", ex);
                }

                await Task.Delay(1000);
            }
        }

        private List<string> GetLogData(List<LogRecord> nodes)
        {
            var gps = nodes.GroupBy(x => x.PLC);
            Dictionary<int, string> output = new Dictionary<int, string>();

            foreach (var gp in gps)
            {
                var plcNodes = gp.ToList();
                int[] index = plcNodes.Select(x => x.SheetColumnIndex).ToArray();
                string[] typ = plcNodes.Select(x => x.DisplayFormat).ToArray();
                var opNodes = plcNodes.Select(x => x.OpcuaNode).ToArray();
                List<string> nds = opNodes.ToList();
                List<string> datas = new List<string>();

                // 读取PLC数据
                var plc = OPCMethod.Instance.GetPlcByName(gp.Key);
                if (plc != null && plc.Connected)
                {
                    //var name = nodes.First().SheetName + gp.Key;
                    //if (!registerWorkLogNodes.ContainsKey(name))
                    //{
                    //    var rd = plc.RegisterVar(nds);
                    //    registerWorkLogNodes.Add(name, rd);
                    //}
                    //datas = plc.ReadData(registerWorkLogNodes[name]);
                    datas = plc.ReadData(nds);
                }
                else
                {
                    datas = Enumerable.Repeat("-1", nds.Count).ToList();
                }
                try
                {
                    for (int i = 0; i < index.Count(); i++)
                    {
                        var node = plcNodes[i];
                        string val = "null";
                        if (!string.IsNullOrEmpty(datas[i]))
                        {
                            switch (typ[i])
                            {
                                case "Logar":
                                    val = double.Parse(datas[i]).ToString("e2");
                                    break;
                                case "Int":
                                    val = Int16.Parse(datas[i]).ToString();
                                    break;
                                case "String":
                                    val = datas[i].ToString();
                                    break;
                                case "Array":
                                    var arrayValues = datas[i].Split(';');
                                    if (node.ArrayIndex < arrayValues.Length)
                                    {
                                        val = arrayValues[node.ArrayIndex];
                                    }
                                    else
                                    {
                                        val = $"索引越界(请求:{node.ArrayIndex}, 数组长度:{arrayValues.Length})";
                                    }
                                    break;
                                default:
                                    val = Math.Round(double.Parse(datas[i]), 2).ToString();
                                    break;
                            }
                        }
                        output.Add(index[i], val);
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Warn($"读取数据地址失败，GetLogData", ex);
                    //GetLogByName("App")?.Error(ex);
                }

            }
            List<string> op = new List<string>();
            var ct = output.Keys.ToList().Max();
            for (int i = 0; i < ct; i++)
            {
                if (output.Any(x => x.Key == i + 1))
                {
                    op.Add(output[i + 1]);
                }
                else
                {
                    op.Add(string.Empty);
                }
            }
            return op;

        }

        private async Task excel_CSV_WriteAsync(string[] args, string title, int titleIndex) //LOG1
        {
            string folderPath1 = $"{OPCMethod.Instance.CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{title}"; //用于判断
            string monthName1 = DateTime.Now.ToString("yyyy-MM"); //用于判断
            string today1 = DateTime.Now.ToString("yyyyMMdd"); //用于判断
            string fileName1 = today1 + ".csv"; //用于判断           
            string monthfile1 = folderPath1 + "\\" + monthName1 + "\\" + fileName1;
            bool fileExists1 = File.Exists(monthfile1); // 检测文件是否存在
            if (!fileExists1)
            {
                CreateFolders(title, titleIndex);
            }
            using (StreamWriter writer = new StreamWriter(monthfile1, true))
            {
                var str = string.Join(",", args);
                await writer.WriteLineAsync(str); // 使用异步写入
            }
        }
        private async Task excel_CSV_WriteLineAsync(string content, string title, int titleIndex) //LOG1
        {
            string folderPath1 = $"{OPCMethod.Instance.CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{title}"; //用于判断
            string monthName1 = DateTime.Now.ToString("yyyy-MM"); //用于判断
            string today1 = DateTime.Now.ToString("yyyyMMdd"); //用于判断
            string fileName1 = today1 + ".csv"; //用于判断           
            string monthfile1 = folderPath1 + "\\" + monthName1 + "\\" + fileName1;
            bool fileExists1 = File.Exists(monthfile1); // 检测文件是否存在
            if (!fileExists1)
            {
                CreateFolders(title, titleIndex);
            }

            using (StreamWriter writer = new StreamWriter(monthfile1, true))
            {
                await writer.WriteLineAsync(content); // 使用异步写入
            }
        }
        private void CreateFolders(string title, int titleIndex)
        {
            string monthName = DateTime.Now.ToString("yyyy-MM");//用于判断
            string today1 = DateTime.Now.ToString("yyyyMMdd");//用于判断
            string folderPath = $"{OPCMethod.Instance.CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{title}";//用于判断
            string fileName = today1 + ".csv";//用于判断
            string filePath = System.IO.Path.Combine(folderPath, fileName);//用于判断
            string monthfile = folderPath + "\\" + monthName + "\\" + fileName;
            if (!Directory.Exists(System.IO.Path.Combine($"{OPCMethod.Instance.CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{title}", monthName)))//判断当前路径是否已经有当月文件夹了

            {
                string rootPath = $"{OPCMethod.Instance.CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{title}";
                // 创建以月份命名的文件夹
                string monthFolderName = DateTime.Now.ToString("yyyy-MM");
                string monthFolderPath = System.IO.Path.Combine(rootPath, monthFolderName);
                Directory.CreateDirectory(monthFolderPath);
            }
            bool fileExists = File.Exists(monthfile); // 检测文件是否存在
            if (!fileExists)
            {
                string monthName2 = DateTime.Now.ToString("yyyy-MM");
                string today = DateTime.Now.ToString("yyyyMMdd");
                string dayFileName = today + ".csv";
                string filePath1 = folderPath + monthName + dayFileName;//用于判断
                string[] columns = ExcelData(titleIndex);
                FileStream fs = new FileStream(monthfile, System.IO.FileMode.Create, System.IO.FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);

                var str = string.Join(",", columns);
                sw.WriteLine(str);
                sw.Close();
                fs.Close();
            }
        }
        public static string[] ExcelData(int sheetN)//string[] args
        {
            Workbook workbook1 = new Workbook();
            workbook1.LoadFromFile($"{AppDomain.CurrentDomain.BaseDirectory}datafiles\\模板\\模板勿删.xlsx");

            var sheet = workbook1.Worksheets[sheetN];
            // 获取第一行的列数
            int columnCount = sheet.Columns.Count();

            // 定义数组，长度为列数
            string[] rowData = new string[columnCount];


            // 遍历所有列，将值保存到数组中
            for (int i = 1; i <= columnCount; i++)
            {
                rowData[i - 1] = sheet.Range[1, i].Value.ToString();
            }
            return rowData;

        }
        #endregion

        private string SelectCsvTime;
        private string AutoRecipeName;//记录配方路径和名称
        private string StartPaC2;//记录C2起始真空
        private string StartPaC3;//记录C3起始真空
        private string StartPaC4;//记录C4起始真空
        private string StartPaC5;//记录C5起始真空

        #region 自动导出批次数据（原始数据计算次数+全量读取）
        #region 导出数据表信息

        private async Task LogToCsvWorkingTask()
        {
            while (ThreadRunning)
            {
                if (!ThreadRunning) break;
                try
                {
                    // 1. 等待PLC触发信号（工艺完成，信号为True）
                    while (ThreadRunning && OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.SaveLogFile_1S") != "True")
                    {
                        await Task.Delay(100);
                    }
                    if (!ThreadRunning) break;

                    // 2. 信号有效，执行导出（基于原始数据计算次数）
                    await Task.Run(() => LogToCSV_BaseOnRawData());

                    // 3. 等待信号复位（避免重复触发）
                    while (ThreadRunning && OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.SaveLogFile_1S") == "True")
                    {
                        await Task.Delay(100);
                    }
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"导出线程异常", ex);
                    await Task.Delay(1000);
                }
            }
        }

        // 基于原始数据计算工艺次数
        private void LogToCSV_BaseOnRawData()
        {
            try
            {
                // 1. 记录当前触发时间（仅用于定位导出日期，不参与工艺判断）
                DateTime triggerTime = DateTime.Now;
                SelectCsvTime = triggerTime.ToString();

                // 2. 构建导出路径（按年月日报组织）
                string baseFolder = Path.Combine(CommonConfigs.LogDataFilePath, "工艺批次数据");
                string yearMonthFolder = triggerTime.ToString("yyyy-MM");
                string dayFolder = triggerTime.ToString("MM-dd");
                string fullExportPath = Path.Combine(baseFolder, yearMonthFolder, dayFolder);
                if (!Directory.Exists(fullExportPath))
                {
                    Directory.CreateDirectory(fullExportPath);
                    GetLogByName("App")?.Info($"自动创建导出文件夹：{fullExportPath}");
                }

                // 3. 读取PLC关键信息（配方、真空值、目标鼓架号）
                ReadPlcProcessInfo();
                string targetDrumInfo = GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.SaveLogFile_ID").ToString();

                // 4. 验证鼓架号有效性
                if (string.IsNullOrEmpty(targetDrumInfo) || !int.TryParse(targetDrumInfo, out _))
                {
                    GetLogByName("App")?.Error("未获取到有效的鼓架编号，取消导出");
                    return;
                }

                // 5. 调用核心导出（读取所有原始数据，从数据中算次数）
                ExportDataToExcel(SelectCsvTime, fullExportPath, targetDrumInfo);
            }
            catch (Exception ex)
            {
                GetLogByName("App")?.Error($"调用导出方法失败", ex);
            }
        }

        // 读取PLC工艺信息（配方+真空值）
        private void ReadPlcProcessInfo()
        {
            try
            {
                AutoRecipeName = OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.Recipe.RecipeName").ToString();
                StartPaC2 = double.Parse(OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.Recipe.C2.rStartPa").ToString()).ToString("0.00E+0");
                StartPaC3 = double.Parse(OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.Recipe.C3.rStartPa").ToString()).ToString("0.00E+0");
                StartPaC4 = double.Parse(OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.Recipe.C4.rStartPa").ToString()).ToString("0.00E+0");
                StartPaC5 = double.Parse(OPCMethod.Instance.GetPlcByName("BeckoffOPC").ReadData("ns=4;s=GVL.Recipe.C5.rStartPa").ToString()).ToString("0.00E+0");
            }
            catch (Exception ex)
            {
                GetLogByName("App")?.Warn($"读取PLC信息失败（不影响数据导出）", ex);
                AutoRecipeName = "配方读取失败";
                StartPaC2 = StartPaC3 = StartPaC4 = StartPaC5 = "真空数据读取失败";
            }
        }

        #endregion

        #region 核心导出功能（按鼓架连续加工周期划分，1次触发导出1个Excel）
        public void ExportDataToExcel(string selectTime, string outputDir, string targetDrumInfo)
        {
            try
            {
                // 解析触发时间（导出日期+触发时分）
                DateTime triggerTime = DateTime.Parse(selectTime);
                DateTime exportDate = triggerTime.Date; // 导出日期（仅年月日）
                string datePart = exportDate.ToString("yyyyMMdd");
                string dateDisplay = exportDate.ToString("yyyy-MM-dd");

                // 1. 获取所有腔体配置
                var configItems = ConfigDbs.LogToCSVRepository.GetAll();
                var chamberGroups = configItems.GroupBy(x => x.Group);
                if (!chamberGroups.Any())
                {
                    GetLogByName("App")?.Error("未获取到腔体配置，取消导出");
                    return;
                }

                // 2. 读取该鼓架已导出的记录（获取上一次结束时间）
                var exportedRecords = GetExportedRecords(outputDir, targetDrumInfo, exportDate);
                DateTime lastExportEndTime = exportDate.AddHours(-1); // 初始值：当天前1小时（确保第一次导出能获取所有段）
                if (exportedRecords.Any())
                {
                    // 取上一次导出的结束时间（最新一次工艺的结束时间）
                    lastExportEndTime = exportedRecords.Last().EndTime;
                    GetLogByName("App")?.Info($"鼓架{targetDrumInfo}上一次导出结束时间：{lastExportEndTime:HH:mm}");
                }
                else
                {
                    GetLogByName("App")?.Info($"鼓架{targetDrumInfo}无历史导出记录，将收集当天所有段");
                }

                // 收集“上一次结束时间之后”的新段数据
                var newDrumSegments = new List<DrumSegment>();
                foreach (var chamberGroup in chamberGroups)
                {
                    string chamberId = chamberGroup.Key;
                    string chamberRootFolder = $"{CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{chamberId}";
                    var headers = chamberGroup
                        .OrderBy(x => int.Parse(x.SheetColumnIndex))
                        .Select(x => x.TitleName)
                        .ToList();

                    // 读取腔体当天全量数据（优化后：支持重试，避免文件占用）
                    var allRecords = ReadAllChamberRecordsByDate(chamberRootFolder, headers, datePart);
                    if (!allRecords.Any())
                    {
                        GetLogByName("App")?.Info($"腔体{chamberId}当天无数据，跳过");
                        continue;
                    }

                    // 提取该腔体中目标鼓架的所有段
                    var allDrumSegmentsInChamber = GetTargetDrumSegments(allRecords, targetDrumInfo);
                    if (!allDrumSegmentsInChamber.Any())
                    {
                        GetLogByName("App")?.Info($"腔体{chamberId}无鼓架{targetDrumInfo}的段，跳过");
                        continue;
                    }

                    // 筛选：只保留“段的开始时间 > 上一次结束时间”的新段
                    foreach (var segment in allDrumSegmentsInChamber)
                    {
                        if (DateTime.TryParse(segment.First()["时间"], out DateTime segStart) &&
                            DateTime.TryParse(segment.Last()["时间"], out DateTime segEnd))
                        {
                            if (segStart > lastExportEndTime)
                            {
                                newDrumSegments.Add(new DrumSegment
                                {
                                    ChamberId = chamberId,
                                    Data = segment,
                                    StartTime = segStart,
                                    EndTime = segEnd
                                });
                                GetLogByName("App")?.Info($"收集新段：腔体{chamberId} 鼓架{targetDrumInfo} {segStart:HH:mm}-{segEnd:HH:mm}（晚于上一次结束时间{lastExportEndTime:HH:mm}）");
                            }
                        }
                    }
                }

                // 无新段数据则退出（没有新工艺）
                if (!newDrumSegments.Any())
                {
                    GetLogByName("App")?.Info($"鼓架{targetDrumInfo}在{lastExportEndTime:HH:mm}之后无新段数据，取消导出");
                    return;
                }

                // 按腔体ID分组（关键修复：避免同一腔体重复创建工作表）
                var segmentsGroupedByChamber = newDrumSegments.GroupBy(s => s.ChamberId).ToList();

                // 确定本次工艺次数（上一次次数+1）
                int currentProcessNum = exportedRecords.Any() ? exportedRecords.Last().ProcessNumber + 1 : 1;

                // 调用方法构建本次周期信息（筛选后的新段即本次周期）
                var currentCycle = CreateCurrentCycle(newDrumSegments, currentProcessNum);
                // 双重防护：若周期创建失败（理论上newDrumSegments已判空，此处为冗余防护）
                if (currentCycle == null)
                {
                    GetLogByName("App")?.Error($"鼓架{targetDrumInfo}周期创建失败，取消导出");
                    return;
                }
                GetLogByName("App")?.Info($"本次导出鼓架{targetDrumInfo}第{currentProcessNum}次周期，时间范围：{currentCycle.CycleStartTime:HH:mm}-{currentCycle.CycleEndTime:HH:mm}");

                // 构建文件名（结束时间取本次周期的最晚结束时间）
                string processEndTime = currentCycle.CycleEndTime.ToString("MM-dd-HHmm");
                string fileName = $"鼓架编号-{targetDrumInfo}-第{currentProcessNum}次工艺-{processEndTime}.xlsx";
                string outputFilePath = Path.Combine(outputDir, fileName);

                // 生成Excel（仅包含新段数据）
                using (var workbook = new XLWorkbook())
                {
                    // 删除默认工作表
                    foreach (var sheetName in workbook.Worksheets.Select(ws => ws.Name).ToList())
                    {
                        workbook.Worksheets.Delete(sheetName);
                    }

                    // 循环“腔体分组”创建工作表（避免重复）
                    foreach (var chamberGroup in segmentsGroupedByChamber)
                    {
                        string chamberId = chamberGroup.Key;
                        var chamberSegments = chamberGroup.ToList(); // 该腔体的所有段
                        var headers = GetChamberHeaders(chamberId);

                        if (headers == null || !headers.Any() || !chamberSegments.Any())
                        {
                            GetLogByName("App")?.Warn($"腔体{chamberId}表头或数据无效，跳过创建工作表");
                            continue;
                        }

                        // 调用修复后的方法，传入该腔体的所有段
                        CreateChamberWorksheet(workbook, chamberId, targetDrumInfo, currentProcessNum, chamberSegments, currentCycle);
                    }

                    // 保存文件
                    if (workbook.Worksheets.Count > 0)
                    {
                        workbook.SaveAs(outputFilePath);
                        GetLogByName("App")?.Info($"导出成功！文件路径：{outputFilePath}（包含{workbook.Worksheets.Count}个腔体工作表）");
                    }
                    else
                    {
                        GetLogByName("App")?.Error($"无有效工作表生成，取消保存文件");
                        return;
                    }
                }

                // 导出完成日志
                GetLogByName("App")?.Info($"=== 导出完成 ===\n" +
                                         $"鼓架编号：{targetDrumInfo}\n" +
                                         $"工艺次数：第{currentProcessNum}次\n" +
                                         $"周期时间范围：{currentCycle.CycleStartTime:HH:mm}-{currentCycle.CycleEndTime:HH:mm}\n" +
                                         $"包含腔体：{string.Join("、", segmentsGroupedByChamber.Select(g => g.Key))}\n" +
                                         $"导出文件：{fileName}\n" +
                                         $"保存路径：{outputDir}\n" +
                                         $"触发时间：{triggerTime:yyyy-MM-dd HH:mm:ss}");
            }
            catch (Exception ex)
            {
                GetLogByName("App")?.Error($"导出过程异常：{ex.Message}", ex);
                throw;
            }
        }

        #region 核心模型
        /// <summary>
        /// 鼓架段模型（存储单个段的关键信息）
        /// </summary>
        private class DrumSegment
        {
            public string ChamberId { get; set; } // 腔体ID
            public List<Dictionary<string, string>> Data { get; set; } // 段原始数据
            public DateTime StartTime { get; set; } // 段开始时间
            public DateTime EndTime { get; set; } // 段结束时间
        }

        /// <summary>
        /// 全局工艺周期模型（对应一个Excel文件）
        /// </summary>
        private class GlobalProcessCycle
        {
            public int ProcessNumber { get; set; } // 工艺次数（第1次、第2次）
            public List<DrumSegment> Segments { get; set; } = new(); // 周期内所有段
            public DateTime CycleStartTime { get; set; } // 周期开始时间（最早段开始）
            public DateTime CycleEndTime { get; set; } // 周期结束时间（最晚段结束）
        }

        /// <summary>
        /// 导出记录模型（存储工艺次数和对应的结束时间，用于分割新周期）
        /// </summary>
        private class ExportedRecord
        {
            public int ProcessNumber { get; set; } // 工艺次数（第1次、第2次）
            public DateTime EndTime { get; set; }   // 该次工艺的结束时间（从文件名解析）
        }
        #endregion

        #region 依赖辅助方法
        /// <summary>
        /// 读取已导出记录（不仅获取工艺次数，还解析每个次数的结束时间）
        /// </summary>
        private List<ExportedRecord> GetExportedRecords(string directory, string drumInfo, DateTime exportDate)
        {
            var exportedRecords = new List<ExportedRecord>();
            if (!Directory.Exists(directory))
                return exportedRecords;

            // 匹配文件名格式：鼓架编号-3-第1次工艺-11-04-1630.xlsx
            var pattern = $"鼓架编号-{drumInfo}-第(\\d+)次工艺-(\\d{2})-(\\d{2})-(\\d{4})\\.xlsx";
            foreach (var file in Directory.GetFiles(directory, "*.xlsx").Select(f => Path.GetFileName(f)))
            {
                var match = Regex.Match(file, pattern);
                if (match.Success)
                {
                    // 解析工艺次数
                    if (!int.TryParse(match.Groups[1].Value, out int processNum))
                        continue;

                    // 解析结束时间（文件名最后4位：HHmm，如1630→16:30）
                    if (!int.TryParse(match.Groups[4].Value, out int endTimeHHmm))
                        continue;
                    int endHour = endTimeHHmm / 100;
                    int endMinute = endTimeHHmm % 100;
                    if (endHour < 0 || endHour >= 24 || endMinute < 0 || endMinute >= 60)
                        continue;

                    // 拼接完整结束时间（导出日期+解析的时分）
                    DateTime endTime = new DateTime(
                        exportDate.Year,
                        exportDate.Month,
                        exportDate.Day,
                        endHour,
                        endMinute,
                        0
                    );

                    exportedRecords.Add(new ExportedRecord
                    {
                        ProcessNumber = processNum,
                        EndTime = endTime
                    });
                }
            }

            // 按工艺次数升序排序（确保取最新一次的结束时间）
            return exportedRecords.OrderBy(r => r.ProcessNumber).ToList();
        }

        /// <summary>
        /// 简化周期划分
        /// </summary>
        private GlobalProcessCycle CreateCurrentCycle(List<DrumSegment> newSegments, int currentProcessNum)
        {
            if (!newSegments.Any())
                return null;

            return new GlobalProcessCycle
            {
                ProcessNumber = currentProcessNum,
                CycleStartTime = newSegments.Min(s => s.StartTime),
                CycleEndTime = newSegments.Max(s => s.EndTime),
                Segments = newSegments
            };
        }

        /// <summary>
        /// 检查“两段间隔内”是否存在其他鼓架的加工记录（核心判断条件）--------手动导出用得到的逻辑
        /// </summary>
        private bool HasOtherDrumRecordsInInterval(DateTime intervalStart, DateTime intervalEnd, string targetDrumInfo, string datePart)
        {
            // 间隔过短（1分钟内）视为连续，直接返回false
            if (intervalEnd.Subtract(intervalStart).TotalMinutes <= 1)
                return false;

            // 遍历所有腔体，检查间隔内是否有其他鼓架记录
            var configItems = ConfigDbs.LogToCSVRepository.GetAll();
            var chamberGroups = configItems.GroupBy(x => x.Group);

            foreach (var chamberGroup in chamberGroups)
            {
                string chamberId = chamberGroup.Key;
                string chamberRootFolder = $"{CommonConfigs.DataFilePath}datafiles\\ExcelSave\\{chamberId}";
                var headers = chamberGroup
                    .OrderBy(x => int.Parse(x.SheetColumnIndex))
                    .Select(x => x.TitleName)
                    .ToList();

                // 读取该腔体在“间隔内”的所有记录
                var intervalRecords = ReadRecordsInTimeRange(chamberRootFolder, headers, intervalStart, intervalEnd);
                if (!intervalRecords.Any())
                    continue;

                // 检查是否有“非目标鼓架”的记录
                bool hasOtherDrum = intervalRecords.Any(r => !r.TryGetValue("鼓架信息", out string drum) || drum != targetDrumInfo);
                if (hasOtherDrum)
                {
                    GetLogByName("App")?.Info($"间隔[{intervalStart:HH:mm}-{intervalEnd:HH:mm}] 腔体{chamberId}存在其他鼓架记录，触发周期分割");
                    return true;
                }
            }

            // 所有腔体间隔内均无其他鼓架记录
            return false;
        }

        /// <summary>
        /// 读取腔体当天全量数据（优化：增加重试机制，避免文件占用）
        /// </summary>
        private List<Dictionary<string, string>> ReadAllChamberRecordsByDate(string chamberRootFolder, List<string> headers, string datePart)
        {
            var allRecords = new List<Dictionary<string, string>>();
            if (!Directory.Exists(chamberRootFolder))
            {
                GetLogByName("App")?.Error($"腔体文件夹不存在：{chamberRootFolder}");
                return allRecords;
            }

            string targetFileName = $"{datePart}.csv";
            var csvFiles = Directory.GetFiles(chamberRootFolder, "*.csv", SearchOption.AllDirectories)
                                    .Where(file => Path.GetFileName(file) == targetFileName)
                                    .ToList();

            foreach (var csvFile in csvFiles)
            {
                try
                {
                    using (var fileStream = new FileStream(csvFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    using (var reader = new StreamReader(fileStream, Encoding.UTF8))
                    {
                        var lines = new List<string>();
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            lines.Add(line);
                        }

                        if (lines.Count <= 1) break;

                        var fileHeaders = lines[0].Split(',').Select(h => h.Trim()).ToList();
                        if (!fileHeaders.SequenceEqual(headers))
                        {
                            GetLogByName("App")?.Error($"表头不匹配：{csvFile}");
                            break;
                        }

                        for (int i = 1; i < lines.Count; i++)
                        {
                            var values = lines[i].Split(',');
                            if (values.Length != headers.Count)
                            {
                                GetLogByName("App")?.Warn($"CSV行数据列数不匹配，跳过：{csvFile} 第{i + 1}行");
                                continue;
                            }

                            var record = new Dictionary<string, string>();
                            for (int j = 0; j < headers.Count; j++)
                            {
                                record[headers[j]] = values[j];
                            }
                            allRecords.Add(record);
                        }
                        break; // 读取成功，退出重试
                    }
                }
                catch (IOException ioEx)
                {
                    GetLogByName("App")?.Error($"读取CSV文件失败：{csvFile} - {ioEx.Message}");
                }
                catch (Exception ex)
                {
                    GetLogByName("App")?.Error($"读取文件错误：{csvFile} - {ex.Message}");
                    break;
                }
            }

            return allRecords.OrderBy(r => DateTime.Parse(r["时间"])).ToList();
        }

        /// <summary>
        /// 读取腔体指定时间范围数据
        /// </summary>
        private List<Dictionary<string, string>> ReadRecordsInTimeRange(string chamberRootFolder, List<string> headers, DateTime startTime, DateTime endTime)
        {
            var timeRangeRecords = new List<Dictionary<string, string>>();
            if (!Directory.Exists(chamberRootFolder))
                return timeRangeRecords;

            var targetDates = Enumerable.Range(0, (endTime.Date - startTime.Date).Days + 1)
                                        .Select(d => startTime.Date.AddDays(d))
                                        .ToList();
            foreach (var targetDate in targetDates)
            {
                string csvFileName = $"{targetDate:yyyyMMdd}.csv";
                string csvFilePath = Path.Combine(chamberRootFolder, csvFileName);
                if (!File.Exists(csvFilePath))
                    continue;

                using (var fileStream = new FileStream(csvFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                using (var reader = new StreamReader(fileStream, Encoding.UTF8))
                {
                    try
                    {
                        var lines = new List<string>();
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            lines.Add(line);
                        }
                        if (lines.Count <= 1)
                            continue;

                        var fileHeaders = lines[0].Split(',').Select(h => h.Trim()).ToList();
                        if (!fileHeaders.SequenceEqual(headers))
                            continue;

                        int timeColIndex = fileHeaders.IndexOf("时间");
                        for (int i = 1; i < lines.Count; i++)
                        {
                            var values = lines[i].Split(',');
                            if (values.Length != headers.Count)
                                continue;

                            if (DateTime.TryParse(values[timeColIndex], out DateTime recordTime) &&
                                recordTime >= startTime && recordTime <= endTime)
                            {
                                var record = new Dictionary<string, string>();
                                for (int j = 0; j < headers.Count; j++)
                                {
                                    record[headers[j]] = values[j];
                                }
                                timeRangeRecords.Add(record);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        GetLogByName("App")?.Error($"读取{chamberRootFolder}\\{csvFileName}时间范围记录异常", ex);
                    }
                }
            }

            return timeRangeRecords.OrderBy(r => DateTime.Parse(r["时间"])).ToList();
        }

        /// <summary>
        /// 创建腔体工作表（修复：同一腔体合并多个段数据）
        /// </summary>
        private void CreateChamberWorksheet(XLWorkbook workbook, string chamberId, string drumInfo, int processNum,
                                         List<DrumSegment> chamberSegments, GlobalProcessCycle processCycle)
        {
            var headers = GetChamberHeaders(chamberId);
            if (headers == null || !headers.Any())
                return;

            var worksheet = workbook.Worksheets.Add(chamberId);
            int currentRow = 1;

            // 标题（显示周期时间+该腔体所有段的时间范围）
            string cycleTime = $"{processCycle.CycleStartTime:HH:mm} - {processCycle.CycleEndTime:HH:mm}";
            string segTimes = string.Join("、", chamberSegments.Select(s => $"{s.StartTime:HH:mm}-{s.EndTime:HH:mm}"));
            worksheet.Cell(currentRow, 1).Value = $"{chamberId} - 鼓架{drumInfo}-第{processNum}次工艺（周期：{cycleTime} | 段：{segTimes}）";
            worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
            currentRow++;

            // 配方信息
            worksheet.Cell(currentRow, 1).Value = $"当前配方:{AutoRecipeName}";
            worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
            currentRow++;

            // 起始真空度（按腔体匹配）
            if (chamberId == "C2工艺中数据")
            {
                worksheet.Cell(currentRow, 1).Value = $"起始真空:{StartPaC2}Pa";
                worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
                currentRow++;
            }
            else if (chamberId == "C3工艺中数据")
            {
                worksheet.Cell(currentRow, 1).Value = $"起始真空:{StartPaC3}Pa";
                worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
                currentRow++;
            }
            else if (chamberId == "C4工艺中数据")
            {
                worksheet.Cell(currentRow, 1).Value = $"起始真空:{StartPaC4}Pa";
                worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
                currentRow++;
            }
            else if (chamberId == "C5工艺中数据")
            {
                worksheet.Cell(currentRow, 1).Value = $"起始真空:{StartPaC5}Pa";
                worksheet.Range(currentRow, 1, currentRow, headers.Count).Merge().Style.Font.Bold = true;
                currentRow++;
            }

            // 写入表头（仅1次）
            for (int i = 0; i < headers.Count; i++)
            {
                worksheet.Cell(currentRow, i + 1).Value = headers[i];
            }
            worksheet.Row(currentRow).Style.Font.Bold = true;
            currentRow++;

            // 按时间顺序写入该腔体的所有段数据
            foreach (var segment in chamberSegments.OrderBy(s => s.StartTime))
            {
                currentRow = WriteDrumEntryData(worksheet, headers, segment.Data, currentRow);
                currentRow++; // 段之间空行分隔，便于查看
            }
        }

        /// <summary>
        /// 写入段数据到工作表
        /// </summary>
        private int WriteDrumEntryData(IXLWorksheet worksheet, List<string> headers, List<Dictionary<string, string>> segment, int startRow)
        {
            int row = startRow;

            foreach (var record in segment)
            {
                for (int i = 0; i < headers.Count; i++)
                {
                    worksheet.Cell(row, i + 1).Value = record.TryGetValue(headers[i], out string value) ? value : "";
                }
                row++;
            }

            return row;
        }

        /// <summary>
        /// 获取腔体表头
        /// </summary>
        private List<string> GetChamberHeaders(string chamberId)
        {
            var configItems = ConfigDbs.LogToCSVRepository.GetAll();
            return configItems
                .Where(x => x.Group == chamberId)
                .OrderBy(x => int.Parse(x.SheetColumnIndex))
                .Select(x => x.TitleName)
                .ToList();
        }

        /// <summary>
        /// 提取目标鼓架的所有段
        /// </summary>
        private List<List<Dictionary<string, string>>> GetTargetDrumSegments(List<Dictionary<string, string>> allRecords, string targetDrumInfo)
        {
            var drumSegments = new List<List<Dictionary<string, string>>>();
            List<Dictionary<string, string>> currentSegment = null;

            foreach (var record in allRecords)
            {
                if (!record.TryGetValue("鼓架信息", out string currentDrum))
                    continue;

                // 目标鼓架：加入当前段
                if (currentDrum == targetDrumInfo)
                {
                    if (currentSegment == null)
                    {
                        currentSegment = new List<Dictionary<string, string>>();
                        drumSegments.Add(currentSegment);
                    }
                    currentSegment.Add(record);
                }
                // 非目标鼓架：结束当前段
                else
                {
                    currentSegment = null;
                }
            }

            return drumSegments;
        }
        #endregion
        #endregion
        #endregion




    }
    #endregion
    public static class JsonOperation
    {
        public static T ReadConfigFromFile<T>(string path)
        {
            using (var file = File.OpenText(path))
            {
                var serializer = new JsonSerializer();
                return serializer.Deserialize<T>(new JsonTextReader(file));
            }
        }

        public static void WriteToJsonFile<T>(T obj, string filePath)
        {
            if (File.Exists(filePath))
                File.Delete(filePath);
            var path = filePath.Replace(filePath.Split("\\").Last(), "");
            Directory.CreateDirectory(path);
            using (var file = new StreamWriter(File.OpenWrite(filePath)))
            {
                JsonSerializerSettings jsetting = new JsonSerializerSettings();
                jsetting.DefaultValueHandling = DefaultValueHandling.Include;
                file.Write(JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented, jsetting));
            }

        }
    }
}
